/**
 * @brief 3.6 多维数组
 * 严格来说，C++语言中没有多维数组，通常所说的多维数组其实是数组的数组。谨记这一点，对今后理解和使用多维数组大有益处。
 */
#include <iostream>
#include <vector>
#include <iterator>
#include <cstddef>
using std::begin, std::end;
using std::cin, std::cout, std::endl;
using std::size_t; // 在cstddef头文件中定义了size_t类型
using std::string;

int main(int argc, char const *argv[])
{
    // 当一个数组的元素仍然是数组时，通常使用两个维度来定义它：'
    // 一个维度表示数组本身大小，另外一个维度表示其元素（也是数组）大小
    int ia[3][4];              // ia大小为3，每个元素是含有4个整数的数组
    int arr[10][20][30] = {0}; // arr大小为10，每个元素都是大小为20的数组，这些数组的元素是含有30个整数的数组

    // 对于二维数组来说，常把第一个维度称作行，第二个维度称作列。
    // 多维数组的初始化
    int ia1[3][4] =
        {
            {0, 1, 2, 3},  // 第1行的初始值
            {4, 5, 6, 7},  // 第2行的初始值
            {8, 9, 10, 11} // 第3行的初始值
        };
    // 其中内层嵌套着的花括号并非必需的
    int ia2[3][4] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};

    // 显示地初始化每行的首元素
    int ia3[3][4] =
        {
            {0}, // 第1行的初始值
            {4}, // 第2行的初始值
            {8}  // 第3行的初始值
        };

    // 显示地初始化第1行，其他元素执行值初始化
    int ia34[3][4] = {0, 3, 6, 9};

    // 多维数组的下标引用
    ia[2][3] = arr[0][0][0]; // 用arr的首元素给ia的最后一行的最后一个元素赋值
    int(&row)[4] = ia[1];    // 把row绑定到ia的第二个4元素数组上

    // 程序中经常会用到两层嵌套的for循环来处理多维数组的元素
    constexpr size_t rowCnt = 3, colCnt = 4;
    int ia4[rowCnt][colCnt];             // 12个未初始化的元素
    for (size_t i = 0; i != rowCnt; ++i) // 循环行
    {
        for (size_t j = 0; j != colCnt; ++j) // 循环列
        {
            ia4[i][j] = i * colCnt + j;
        }
    }

    // 使用范围for循环处理多维数组
    // 上一个两层嵌套for循环可简化为如下
    size_t cnt = 0;
    for (auto &row : ia4)
    {
        for (auto &col : row)
        {
            col = cnt;
            ++cnt;
        }
    }
    // 要使用范围for语句处理多维数组，除了最内层的循环外，其他所有循环的控制变量都应该是引用类型。

    // 指针和多维数组
    // 当程序使用多维数组的名字时，也会自动将其转换成指向数组首元素的指针。
    int ia5[3][4];
    int(*p)[4] = ia5; // p指向含有4个整数的数组
    p = &ia5[2];      // p指向ia5的尾元素

    // 随着C++11新标准的提出，通过使用auto或者decltype（参见2.5.2节，第61页）就能尽可能地避免在数组前面加上一个指针类型了
    for (auto p = ia5; p != (ia5 + 3); ++p) // p指向含有4个整数的数组
    {
        for (auto q = *p; q != (*p + 4); ++q) // q指向4个整数数组的首元素，也即是说q指向一个整数
        {
            cout << *q << ' ';
        }
        cout << endl;
    }

    // 当然，使用标准库函数begin和end（参见3.5.3节，第106页）也能实现上面同样的功能，而且看起来更简洁一些
    for (auto p = begin(ia5); p != end(ia5); ++p)
    {
        for (auto q = begin(*p); q != end(*p); ++q)
        {
            cout << *q << ' ';
        }
        cout << endl;
    }

    // 类型别名简化多维数组的指针
    using int_array = int[4];  // 新标准下类型别名的声明
    typedef int int_array1[4]; // 等价的typedef声明
    for (int_array *p = ia5; p != ia5 + 3; ++p)
    {
        for (int *q = *p; q != *p + 4; ++q)
        {
            cout << *q << ' ';
        }
        cout << endl;
    }

    return 0;
}
